package javabase.demo03;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class MultithreadingExercises {
    public static void main(String[] args) throws Exception {
        // 练习1: 生产者-消费者问题
        producerConsumerProblem();

        // 练习2: 读者-写者问题
        readerWriterProblem();

        // 练习3: 哲学家就餐问题
        diningPhilosophersProblem();

        // 练习4: 高性能计数器
        highPerformanceCounter();

        // 练习5: 并行处理任务
        parallelTaskProcessing();
    }


    // 生产者-消费者问题
    private static void producerConsumerProblem() throws InterruptedException {
        System.out.println("\n=== 生产者-消费者问题 ===");

        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);

        // 生产者
        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    queue.put(i);
                    System.out.println("生产: " + i + "，队列大小: " + queue.size());
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 消费者
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    Integer item = queue.take();
                    System.out.println("消费: " + item + "，队列大小: " + queue.size());
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.start();
        consumer.start();

        producer.join();
        consumer.join();
    }


    // 读者-写者问题
    private static void readerWriterProblem() {
        System.out.println("\n=== 读者-写者问题 ===");

        ReadWriteLock lock = new ReentrantReadWriteLock();
        List<Integer> data = new ArrayList<>();

        // 写者
        Thread writer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                lock.writeLock().lock();
                try {
                    data.add(i);
                    System.out.println("写入: " + i);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.writeLock().unlock();
                }
            }
        });

        // 读者
        for (int i = 0; i < 3; i++) {
            final int readerId = i;
            new Thread(() -> {
                for (int j = 0; j < 5; j++) {
                    lock.readLock().lock();
                    try {
                        if (!data.isEmpty()) {
                            System.out.println("读者" + readerId + "读取: " +
                                    data.get(data.size() - 1));
                        }
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.readLock().unlock();
                    }
                }
            }).start();
        }

        writer.start();
    }

    // 哲学家就餐问题
    private static void diningPhilosophersProblem() {
        System.out.println("\n=== 哲学家就餐问题 ===");

        int philosopherCount = 5;
        ReentrantLock[] chopsticks = new ReentrantLock[philosopherCount];
        for (int i = 0; i < philosopherCount; i++) {
            chopsticks[i] = new ReentrantLock();
        }

        ExecutorService executor = Executors.newFixedThreadPool(philosopherCount);

        for (int i = 0; i < philosopherCount; i++) {
            final int philosopherId = i;
            executor.execute(() -> {
                ReentrantLock leftChopstick = chopsticks[philosopherId];
                ReentrantLock rightChopstick = chopsticks[(philosopherId + 1) % philosopherCount];

                try {
                    while (true) {
                        // 思考
                        System.out.println("哲学家" + philosopherId + "思考中");
                        Thread.sleep(1000);

                        // 就餐
                        if (leftChopstick.tryLock(100, TimeUnit.MILLISECONDS)) {
                            try {
                                if (rightChopstick.tryLock(100, TimeUnit.MILLISECONDS)) {
                                    try {
                                        System.out.println("哲学家" + philosopherId + "就餐中");
                                        Thread.sleep(1000);
                                    } finally {
                                        rightChopstick.unlock();
                                    }
                                }
                            } finally {
                                leftChopstick.unlock();
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 运行一段时间后关闭
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executor.shutdownNow();
    }

    // 高性能计数器
    private static void highPerformanceCounter() throws InterruptedException {
        System.out.println("\n=== 高性能计数器 ===");

        int threadCount = 10;
        int incrementPerThread = 100000;

        // 1. 使用synchronized
        long startTime = System.currentTimeMillis();
        SynchronizedCounter synchronizedCounter = new SynchronizedCounter();
        testCounterPerformance(synchronizedCounter, threadCount, incrementPerThread);
        long synchronizedTime = System.currentTimeMillis() - startTime;

        // 2. 使用AtomicLong
        startTime = System.currentTimeMillis();
        AtomicLong atomicCounter = new AtomicLong();
        testCounterPerformance(atomicCounter, threadCount, incrementPerThread);
        long atomicTime = System.currentTimeMillis() - startTime;

        // 3. 使用LongAdder (Java 8+)
        startTime = System.currentTimeMillis();
        LongAdder adderCounter = new LongAdder();
        testCounterPerformance(adderCounter, threadCount, incrementPerThread);
        long adderTime = System.currentTimeMillis() - startTime;

        System.out.println("synchronized耗时: " + synchronizedTime + "ms");
        System.out.println("AtomicLong耗时: " + atomicTime + "ms");
        System.out.println("LongAdder耗时: " + adderTime + "ms");
    }

    private static void testCounterPerformance(Object counter, int threadCount, int incrementPerThread)
            throws InterruptedException {
        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < incrementPerThread; j++) {
                    if (counter instanceof SynchronizedCounter) {
                        ((SynchronizedCounter) counter).increment();
                    } else if (counter instanceof AtomicLong) {
                        ((AtomicLong) counter).incrementAndGet();
                    } else if (counter instanceof LongAdder) {
                        ((LongAdder) counter).increment();
                    }
                }
            });
        }

        for (Thread thread : threads) {
            thread.start();
        }

        for (Thread thread : threads) {
            thread.join();
        }
    }

    static class SynchronizedCounter {
        private long count = 0;

        public synchronized void increment() {
            count++;
        }

        public synchronized long getCount() {
            return count;
        }
    }

    // 并行处理任务
    private static void parallelTaskProcessing() throws Exception {
        System.out.println("\n=== 并行处理任务 ===");

        int taskCount = 10;
        ExecutorService executor = Executors.newFixedThreadPool(4);
        CompletionService<String> completionService = new ExecutorCompletionService<>(executor);

        // 提交任务
        for (int i = 0; i < taskCount; i++) {
            final int taskId = i;
            completionService.submit(() -> {
                int sleepTime = 1000 + new Random().nextInt(2000);
                Thread.sleep(sleepTime);
                return "任务" + taskId + "完成，耗时" + sleepTime + "ms";
            });
        }

        // 获取结果
        for (int i = 0; i < taskCount; i++) {
            Future<String> future = completionService.take();
            System.out.println(future.get());
        }

        executor.shutdown();
    }
}
